/**
 * @file des.c
 * @brief T1 DES Driver
 *
 * @author yemt@witsi.cn
 * @date 2011-08-13
 * @version T1.AES.01
 */
#include "t1_crypto.h"
#include "iodev.h"
#include "ioctl.h"
#include <string.h>
#include "clk.h"
#include "config.h"

static inline void des_copy(uint8_t *dst, uint8_t *src, int length)
{
        dst += length;

        while(length-- > 0){
            *(--dst) = *(src++);
        }
}

static void des_process(uint8_t * data, size_t len)
{
        des_copy(DES_IN, data, len);
        DES->CCFG =  DES_EN | DES_START |(DES->CCFG  & DES_DEC_EN);
        while(!(DES->INT_STA & DES_DONE));
        DES->INT_CLR |= DES_DONE;
}

static int des_init(void)
{
        DES->INT_EN |= DES_DONE;
        DES->INT_MSK &= ~DES_DONE;
        return 0;
}

static ssize_t des_read(iodev_t *dev, void *buffer, size_t size)
{
        ssize_t len = size;

        if (size > DES_OUT_LEN)
                len = DES_OUT_LEN;
        des_copy(buffer, DES_OUT, len);
        memset(DES_OUT, 0x00, DES_OUT_LEN);

        return len;
}

static ssize_t des_write(iodev_t *dev, const void* buffer, size_t size)
{
        ssize_t len = 0;

        if (size < DES_IN_LEN)
                return 0;
        else if(size >= DES_IN_LEN)
                len = DES_IN_LEN;         	/*Data Default Len: 8bytes*/
        des_process((uint8_t *)buffer, len );

        return len;
}

static int des_ioctl(iodev_t *dev, uint32_t cmd, void *arg)
{
        switch (cmd) {
        case IOCTL_CRYPTO_SET_KEY:
                if (arg)
                        des_copy(DES_KEY, (uint8_t *)arg, DES_KEY_LEN);
                break;
        case IOCTL_CRYPTO_SET_ENCRYPT:
		DES->CCFG &= ~DES_DEC_EN;
                break;
        case IOCTL_CRYPTO_SET_DECRYPT:
		DES->CCFG |=  DES_DEC_EN;
                break;
        case IOCTL_CRYPTO_START:
                __enable_crypto_clk();
                des_init();
                break;
        case IOCTL_CRYPTO_STOP:
                __disable_crypto_clk();
                break;
        default:
                break;

        }

        return 0;
}


static const iodev_t T1_des __iodev_entry = {
        .name = "des",
        .priv = NULL,
        .init = NULL,
        .read = des_read,
        .write = des_write,
        .ioctl = des_ioctl,
        .poll = NULL,
#ifdef CONFIG_POWER_CTL
        .suspend = NULL,
        .wakeup = NULL,
#endif
};

